#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<ctime>
#define NUM_THREADS 6

using namespace std;

typedef struct{
	unsigned int N;	// total points
	long double pi,
	dist,	// distance
	x,	// x value
	y;	// y value
	unsigned int in;
}dados;

void *setaN(void *);
void *setaIN(void *);
void *calculaX(void *);
void *calculaY(void *);
void *calculaDIST(void *);
void *calculaIN(void *);
void *calculaPI(void *);

int main(int argc,char** argv){
	
	if(argc < 2){
		cout << "usage: ./prog <interations>" << endl;
		return -1;
	}


	dados var;
	pthread_t threads[NUM_THREADS];
	
	pthread_create(&threads[0], NULL, setaN, (void*)&var.N);
	pthread_create(&threads[1], NULL, setaIN, (void*)&var.in);

	srand(time(NULL));

	for(int i = 0; i < var.N; i++){
		pthread_create(&threads[2], NULL, calculaX, (void*)&var.x);
		pthread_create(&threads[3], NULL, calculaY, (void*)&var.y);
		/*
		x = (double) rand()/RAND_MAX;
		y = (double) rand()/RAND_MAX;
		*/
		pthread_join(threads[2], NULL);
		pthread_join(threads[3], NULL);
		pthread_create(&threads[4], NULL, calculaDIST, (void*)&var);
		pthread_join(threads[4], NULL);
		//dist = sqrt(pow(x,2) + pow(y,2));

		if(var.dist <= 1){
			pthread_create(&threads[5], NULL, calculaIN, (void*)&var.in);
			pthread_join(threads[5], NULL);
		}
	}
	
	pthread_create(&threads[6], NULL, calculaPI, (void*)&var);
	pthread_join(threads[6], NULL);
	// pi =(double) 4 * in/N;

	cout.precision(7);
	cout << "pi:" << var.pi << endl;

	return 0;
}


void *setaN(void *valor){
	unsigned int *aux = (unsigned int *) valor;
	
	// N = 10000000;
	*aux = 10000000; 
	pthread_exit(NULL);
}

void *setaIN(void *valor){
	unsigned int *aux = (unsigned int *) valor;
	
	// in = 0;
	*aux = 0; 
	pthread_exit(NULL);
}

void *calculaX(void *valor){
	long double *aux = (long double *) valor;
	
	// x = (double) rand()/RAND_MAX;
	*aux = (long double) rand() / RAND_MAX;
	pthread_exit(NULL);
}

void *calculaY(void *valor){
	long double *aux = (long double *) valor;
	
	// y = (double) rand()/RAND_MAX;
	*aux = (double) rand() / RAND_MAX;
	pthread_exit(NULL);
}

void *calculaDIST(void *valor){
	dados *f = (dados*) valor;
	long double aux = f->dist;
	long double aux2 = f->x;
	long double aux3 = f->y;
	
	// dist = pow(x,2) + pow(y,2);
	aux = pow(aux2, 2) + pow(aux3, 2);
	f->dist = aux;
	pthread_exit(NULL);
}

void *calculaIN(void *valor){
	unsigned int *aux = (unsigned int *) valor;
	
	// in = in + 1;
	*aux = *aux + 1;
	pthread_exit(NULL);
}

void *calculaPI(void *valor){
	dados *f = (dados*) valor;
	long double aux = f->pi;
	long double aux2 = f->in;
	long double aux3 = f->N;
	
	// pi = 4 * in / N;
	aux = 4 * aux2 / aux3;
	f->pi = aux;
	pthread_exit(NULL);
}
